package by.demchenko.sample.dataaccess.impl;

import by.demchenko.sample.dataaccess.base.ScheduleDao;
import by.demchenko.sample.datamodel.*;
import org.springframework.stereotype.Repository;

import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Root;
import java.util.Date;
import java.util.List;

@Repository
public class ScheduleDaoImpl extends AbstractDaoImpl<Integer, Schedule> implements ScheduleDao {

    protected ScheduleDaoImpl() {
        super(Schedule.class);
    }

    @Override
    public Schedule findRecord(Course course, Date date) {
        CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

        CriteriaQuery<Schedule> root = cBuilder.createQuery(Schedule.class);
        Root<Schedule> criteria = root.from(Schedule.class);

        root.select(criteria);
        criteria.fetch(Schedule_.students);
        root.where(
                cBuilder.and(
                        cBuilder.equal(criteria.get(Schedule_.course), course),
                        cBuilder.equal(criteria.get(Schedule_.startDate), date)
                )
        );
        TypedQuery<Schedule> query = getEm().createQuery(root);
        Schedule result;
        try {
            result = query.getSingleResult();
        } catch (javax.persistence.NoResultException e) {
            return null;
        }
        return result;
    }

    @Override
    public int getCount() {
        CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

        CriteriaQuery<Long> criteria = cBuilder.createQuery(Long.class);
        Root<Schedule> root = criteria.from(Schedule.class);

        criteria.select(cBuilder.count(root));

        TypedQuery<Long> query = getEm().createQuery(criteria);
        return query.getSingleResult().intValue();

    }

    @Override
    public List<Schedule> findByTeacher(Person teacher) {
        CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

        CriteriaQuery<Schedule> criteria = cBuilder.createQuery(Schedule.class);
        Root<Schedule> root = criteria.from(Schedule.class);

        criteria.select(root);
        root.fetch(Schedule_.course);
        criteria.distinct(true);

        criteria.where(cBuilder.equal(root.get(Schedule_.course).get(Course_.teacher), teacher));

        TypedQuery<Schedule> query = getEm().createQuery(criteria);

        return query.getResultList();

    }

    @Override
    public List<Person> getRegisteredStudents(Schedule schedule) {
        CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

        CriteriaQuery<Person> criteria = cBuilder.createQuery(Person.class);
        Root<Person> root = criteria.from(Person.class);

        criteria.select(root);
        //root.fetch(Person_.schedules).fetch(Schedule_.id);
        Join<Person,Schedule> schedul = root.join(Person_.schedules);
        //root.join(Person_.schedules);
        //criteria.distinct(true);

        criteria.where(cBuilder.equal(schedul, schedule));

        TypedQuery<Person> query = getEm().createQuery(criteria);

        return query.getResultList();
    }

    @Override
    public int getCountByTeacher(Person teacher) {
        CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

        CriteriaQuery<Long> criteria = cBuilder.createQuery(Long.class);
        Root<Schedule> root = criteria.from(Schedule.class);

        criteria.select(cBuilder.count(root));
        criteria.where(cBuilder.equal(root.get(Schedule_.course).get(Course_.teacher), teacher));

        TypedQuery<Long> query = getEm().createQuery(criteria);
        return query.getSingleResult().intValue();
    }
}